package install.manage;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.channels.FileChannel;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Scanner;
import org.apache.commons.codec.binary.Base64;
import java.util.stream.Stream;
import org.apache.http.client.utils.URLEncodedUtils;
import java.net.URLEncoder;
import java.net.URLDecoder;
import android.os.Messenger;

public class InstallActivity extends Activity
{

	Scanner in = new Scanner(System.in);
	AdbConnection adb;
	Socket sock;
	AdbCrypto crypto;
	AdbStream stream;
	TextView debug,state;
	ProgressBar progress;
    @Override
    protected void onCreate(Bundle savedInstanceState)
	{
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

		Intent intent = getIntent();
		if (intent == null)
		{this.finish();return;}
		else if (intent.getAction().equals(intent.ACTION_MAIN))
		{this.finish();return;}
		debug = findViewById(R.id.debug);
		state = findViewById(R.id.state);
		progress = findViewById(R.id.progressBar);


		//debug.setText(intent.toString());

		final String apkPath = new String(URLDecoder.decode(intent.getDataString().replace("file://", "")));
		//final String apkPath = new String(URLDecoder.decode(intent.getDataString().replace("file://", "")));
		//String tmp = "/storage/emulated/0/MT2/apks/MT2.9.0.apk";
		//final String apkPath=tmp;
		final File file = new File(apkPath);
		//final String beforeName = file.getName();
		String afterName = String.valueOf(System.currentTimeMillis()) + ".apk";
		final File apk = new File(file.getParent() + "/" + afterName);

		final File apk2 = new File("/data/local/tmp/" + afterName);
		//nioTransferCopy(apk, new File("/data/local/tmp/"+"/tmp.apk"));


	    // Setup the crypto object required for the AdbConnection
		try
		{
			String path = this.getFilesDir().getAbsolutePath() + "/";
			crypto = setupCrypto("pub.key", "priv.key", path);
		}
		catch (NoSuchAlgorithmException e)
		{
			fail(e.toString());
			return;
		}
		catch (InvalidKeySpecException e)
		{
			fail(e.toString());
			return;
		}
		catch (IOException e)
		{
			fail(e.toString());
			return;
		}


		// Start the receiving thread
		new Thread(new Runnable() {
				@Override
				public void run()
				{
					try
					{
						sock = new Socket("127.0.0.1", 5555);
					}
					catch (UnknownHostException e)
					{
						fail(e.toString());
						return;
					}
					catch (IOException e)
					{
						fail(e.toString());
						return;
					}

					// Construct the AdbConnection object
					try
					{
						adb = AdbConnection.create(sock, crypto);
					}
					catch (IOException e)
					{
						fail(e.toString());
						return;
					}

					// Start the application layer connection process
					System.out.println("ADB connecting...");
					debug("ADB connecting...");
					try
					{
						adb.connect();
					}
					catch (IOException e)
					{
						fail(e.toString());
						return;
					}
					catch (InterruptedException e)
					{
						debug(e.toString());
						return;
					}
					System.out.println("ADB connected");

					debug("ADB connected");

					// Open the shell stream of ADB

					try
					{
						Thread.sleep(1000);
					}
					catch (InterruptedException e)
					{}
					try
					{
						stream = adb.open("shell:");
					}
					catch (UnsupportedEncodingException e)
					{
						fail(e.toString());
						return;
					}
					catch (IOException e)
					{
						fail(e.toString());
						return;
					}
					catch (InterruptedException e)
					{
						fail(e.toString());
						return;
					}

					if (!file.renameTo(apk))
                    {
						fail("安装包处理失败");
					}
					try
					{
						stream.write(" cp " + apk.getAbsoluteFile().toString() + " " + apk2.getAbsoluteFile().toString() + '\n');
					}
					catch (IOException e)
					{fail(e.toString());}
					catch (InterruptedException e)
					{fail(e.toString());}
					boolean copyState = false;
                    String sb = "";
					while (!stream.isClosed())
					{
						try
						{
							// Print each thing we read from the shell stream
							String str = new String(stream.read(), "US-ASCII");
                            if(str.contains("\n")){
                                String[] strs=  str.split("\n");
                                
                                for(int i =0 ;i< strs.length;i++){
                                    if(i==0){
                                        sb=sb+strs[0];
                                        debug(sb);
                                        sb = "";
                                    } else if(i==strs.length-1){
                                        sb = sb+strs[i];
                                    }else{
                                        debug(strs[i]);
                                        sb="";
                                    }
                                }
                            }else{
                                sb = sb+str;
                            }


							if (str.contains("cp"))
                            {
								if (copyState == false)
                                {
									copyState = true;
								}
                                else
                                {
									stream.write(" pm install -r " + apk2.getAbsoluteFile() + '\n');
								}

							}
							if (str.contains("Success"))
                            {
								handler.sendEmptyMessage(2000);
								apk.renameTo(new File(apkPath));
								stream.write(" rm -rf " + apk2.getAbsolutePath() + "\n");
								stream.write(" exit" + "\n");
								apk2.delete();
							}
                            else if (str.contains("Error") | str.contains("error") | str.contains("fail") | str.contains("Fail"))
                            {
								apk.renameTo(new File(apkPath));
								stream.write(" rm -rf" + apk2.getAbsolutePath() + "\n");
								stream.write(" exit" + "\n");
								fail(str);
							}
							//System.out.print(new String(stream.read(), "US-ASCII"));
						}
						catch (UnsupportedEncodingException e)
						{
							fail(e.toString());
							return;
						}
						catch (InterruptedException e)
						{
							fail(e.toString());
							return;
						}
						catch (IOException e)
						{
							return;
						}
					}

					// We become the sending thread

				}
			}).start();
	}

	@Override
	protected void onDestroy()
	{
		// TODO: Implement this method
		super.onDestroy();
		try
		{
			if (adb != null)
            {adb.close();}
		}
		catch (IOException e)
		{}
	}



	Handler handler = new Handler(){

		@Override
		public void handleMessage(Message msg)
		{
			// TODO: Implement this method
			super.handleMessage(msg);
            if (msg.obj != null)
            {
                String reg = regular(msg.obj.toString());
                if (reg != null)
                {
                    debug.append(reg + "\n");
                }
			}
			if (msg.what == 2000)
            {
				//安装完成
				progress.setVisibility(View.GONE);
				state.setTextAppearance(android.R.attr.textAppearanceLarge);
				state.setText("Install Finished");

			}
            else if (msg.what == 3000)
            {
				//安装失败
				String reason = msg.obj.toString();
				progress.setVisibility(View.GONE);
				state.setText("Install Fail:" + reason);
			}

			if (msg.what == 2000 || msg.what == 3000)
            {
				new Thread(new Runnable(){

						@Override
						public void run()
						{
							// TODO: Implement this method
							try
							{
								Thread.sleep(3000);
								finish();
							}
							catch (InterruptedException e)
							{}
						}
					}).start();
			}
		}};

    String regular(String string)
    {
        if (string == null)
        {
            return string;
        }
        if (string.equals("^@"))
        {
            return null;
        }
        
        if(string.contains("^@")){
            string = string.replaceAll("^@","");
        }

        if (string.contains("\n"))
        {
            string = string.replaceAll("\n", "");
        }

        if (string.contains("$"))
        {
            string = string.replaceAll("^.*?\\$", "");
        }
        
        if(string.contains(" ")){
            string = string.replace("^ *","");
        }
        
        if(string.contains("<")){
            string = string.replace(" *<*","");
            string = string.replace("","");
        }

        
        return string.trim();
    }

    // This implements the AdbBase64 interface required for AdbCrypto
	public static AdbBase64 getBase64Impl()
	{
		return new AdbBase64() {
			@Override
			public String encodeToString(byte[] arg0)
			{
				return Base64.encodeBase64(arg0).toString();
			}
		};
	}

	// This function loads a keypair from the specified files if one exists, and if not,
	// it creates a new keypair and saves it in the specified files
	private static AdbCrypto setupCrypto(String pubKeyFile, String privKeyFile, String path)
	throws NoSuchAlgorithmException, InvalidKeySpecException, IOException
	{


		File pub = new File(path + pubKeyFile);
		File priv = new File(path + privKeyFile);
		AdbCrypto c = null;

		// Try to load a key pair from the files 
//		if (pub.exists() && priv.exists())
//		{
//			try
//			{
//				c = AdbCrypto.loadAdbKeyPair(InstallActivity.getBase64Impl(), priv, pub);
//			}
//			catch (IOException e)
//			{
//				// Failed to read from file
//				c = null;
//			}
//			catch (InvalidKeySpecException e)
//			{
//				// Key spec was invalid
//
//				c = null;
//			}
//			catch (NoSuchAlgorithmException e)
//			{
//				// RSA algorithm was unsupported with the crypo packages available
//				c = null;
//			}
//		}

		if (c == null)
		{
			// We couldn't load a key, so let's generate a new one
			c = AdbCrypto.generateAdbKeyPair(InstallActivity.getBase64Impl());

			// Save it
			c.saveAdbKeyPair(priv, pub);
			System.out.println("Generated new keypair");
		}
		else
		{
			System.out.println("Loaded existing keypair");
		}

		return c;
	}

	void debug(Object obj)
	{
		Message msg = new Message();
		msg.obj = obj;
		handler.sendMessage(msg);
	}

	void fail(Object str)
    {
		Message msg3 = new Message();
		msg3.obj = str.toString();
		msg3.what = 3000;
		handler.sendMessage(msg3);
	}

	static void close(FileChannel s)
    {
		try
		{
			if (s != null)
            {
				s.close();
			}

		}
		catch (IOException e)
		{}
	}
	static void close(FileInputStream s)
    {
		if (s != null)
        {
			try
			{
				s.close();
			}
			catch (IOException e)
			{}
		}

	}

	static void close(FileOutputStream s)
    {
		if (s != null)
        {
			try
			{
				s.close();
			}
			catch (IOException e)
			{}
		}

	}



}
